﻿namespace WebPacker.Tests
{
	using System;
	using Moq;
	using NUnit.Framework;
	using WebPacker.Helpers;
	using WebPacker.Packs;
	using WebPacker.Packs.Resources;
	using WebPacker.VersionGenerators;

	[TestFixture]
	public class WebPackerHtmlTest
	{
		[SetUp]
		public void Setup()
		{
			VirtualPathHelper.ApplicationPhysicalPath = @"c:\webapp\app";
			VirtualPathHelper.ApplicationVirtualPath = "/app";
			WebPackerRouter.Instance = new Mock<IPackRouter>(MockBehavior.Strict).Object;
		}

		[Test]
		public void ScriptPackTest()
		{
			var mock = new Mock<IPackRouter>();
			mock.Setup(x => x.Enabled).Returns(true);
			mock.Setup(x => x.GetUrl(null, PackType.JavaScript, "js")).Returns("/app/content/script.js?v=123");
			WebPackerRouter.Instance = mock.Object;

			var actual = WebPackerHtml.ScriptPack("js");
			var expected = "<script type=\"text/javascript\" src=\"/app/content/script.js?v=123\"></script>";
			Assert.IsNotNull(actual);
			Assert.AreEqual(expected, actual);
		}

		[Test]
		public void CssPackTest()
		{
			var mock = new Mock<IPackRouter>();
			mock.Setup(x => x.Enabled).Returns(true);
			mock.Setup(x => x.GetUrl(null, PackType.Css, "css")).Returns("/app/content/style.css?v=123");
			WebPackerRouter.Instance = mock.Object;
			var actual = WebPackerHtml.CssPack("css");
			var expected = "<link href=\"/app/content/style.css?v=123\" rel=\"stylesheet\" type=\"text/css\" />";
			Assert.IsNotNull(actual);
			Assert.AreEqual(expected, actual);
		}

		[Test]
		public void ScriptPackExceptionRecoveryTest()
		{
			var mock = new Mock<IPackRouter>();
			mock.Setup(x => x.Enabled).Returns(true);
			mock.Setup(x => x.GetPack(PackType.JavaScript, "js")).Returns(GetJavaScriptPack("js"));
			mock.Setup(x => x.GetUrl(null, PackType.JavaScript, "js")).Returns<string>(null);
			WebPackerRouter.Instance = mock.Object;

			// webpacker must switch to resources
			var actual = WebPackerHtml.ScriptPack("js");
			AssertPackByResources(PackType.JavaScript, actual);
		}

		[Test]
		public void CssPackExceptionRecoveryTest()
		{
			var mock = new Mock<IPackRouter>();
			mock.Setup(x => x.Enabled).Returns(true);
			mock.Setup(x => x.GetUrl(null, PackType.Css, "css")).Returns<string>(null);
			mock.Setup(x => x.GetPack(PackType.Css, "css")).Returns(GetCssPack("css"));
			WebPackerRouter.Instance = mock.Object;

			// webpacker must switch to resources
			var actual = WebPackerHtml.CssPack("css");
			AssertPackByResources(PackType.Css, actual);
		}

		[Test]
		public void ScriptPackByResourcesTest()
		{
			var mock = new Mock<IPackRouter>();
			mock.Setup(x => x.Enabled).Returns(true);
			mock.Setup(x => x.GetPack(PackType.JavaScript, "js")).Returns(GetJavaScriptPack("js"));
			WebPackerRouter.Instance = mock.Object;

			var actual = WebPackerHtml.ScriptPack(new string[] { "~/content/test.js", "http://google.com/script.js" });
			AssertPackByResources(PackType.JavaScript, actual);
		}

		[Test]
		public void CssPackByResourcesTest()
		{
			var mock = new Mock<IPackRouter>();
			mock.Setup(x => x.Enabled).Returns(true);
			mock.Setup(x => x.GetPack(PackType.Css, "css")).Returns(GetCssPack("css"));
			WebPackerRouter.Instance = mock.Object;

			var actual = WebPackerHtml.CssPack(new string[] { "~/content/mystyle.css", "http://google.com/style.css" });
			AssertPackByResources(PackType.Css, actual);
		}

		[Test]
		public void ScriptPackDisabledTest()
		{
			var mock = new Mock<IPackRouter>();
			mock.Setup(x => x.Enabled).Returns(false);
			mock.Setup(x => x.GetPack(PackType.JavaScript, "js")).Returns(GetJavaScriptPack("js"));
			WebPackerRouter.Instance = mock.Object;

			var actual = WebPackerHtml.ScriptPack("js");
			AssertPackByResources(PackType.JavaScript, actual);
		}

		[Test]
		public void CssPackDisabledTest()
		{
			var mock = new Mock<IPackRouter>();
			mock.Setup(x => x.Enabled).Returns(false);
			mock.Setup(x => x.GetPack(PackType.Css, "css")).Returns(GetCssPack("css"));
			WebPackerRouter.Instance = mock.Object;
			var actual = WebPackerHtml.CssPack("css");
			AssertPackByResources(PackType.Css, actual);
		}

		private void AssertPackByResources(PackType packType, string actual)
		{
			Assert.IsNotNull(actual);
			actual = actual.Replace("\r", string.Empty).Replace("\n", string.Empty);

			string expected;

			if (packType == PackType.JavaScript)
			{
				expected = "<script type=\"text/javascript\" src=\"/app/content/test.js\"></script><script type=\"text/javascript\" src=\"http://google.com/script.js\"></script>";
			}
			else
			{
				expected = "<link href=\"/app/content/mystyle.css\" rel=\"stylesheet\" type=\"text/css\" /><link href=\"http://google.com/style.css\" rel=\"stylesheet\" type=\"text/css\" />";
			}

			Assert.AreEqual(expected, actual);
		}

		private Pack GetCssPack(string packName)
		{
			var resources = new IResource[] { new FileResource(@"C:\webapp\app\content\mystyle.css"), new RemoteResource("http://google.com/style.css") };
			return new Pack(PackType.Css, packName, resources, new TestFilter(PackType.Css), null, new ManualVersionGenerator(), "test");
		}

		private Pack GetJavaScriptPack(string packName)
		{
			var resources = new IResource[] { new FileResource(@"C:\webapp\app\content\test.js"), new RemoteResource("http://google.com/script.js") };
			return new Pack(PackType.JavaScript, packName, resources, new TestFilter(PackType.JavaScript), null, new ManualVersionGenerator(), "test");
		}
	}
}
